/*Metodo de monte carlo sequencial*/

#include<stdio.h>
#include<stdlib.h>
#include<time.h> //pra semente do rand
#include<sys/time.h>
#include<gmp.h> //biblioteca pra obter precisao gigante

#define MAX_INT 1577 //numero de interacoes do metodo pré definido, se formos fazer por erro relativo o programa vai continuar rodando por algumas decadas, e provavelmente o computador vai ter quebrado antes de dar o resultado...






int main() {

    //VARIAVEIS PARA GUARDAR O TEMPO
    int tempo;
    struct timeval inicio, fim;

    unsigned long int i;
    mpf_t n;
    mpf_t x, y;
    mpf_t Pin;
    mpf_t Pi;

    /*variaveis auxiliares*/
    mpf_t aux, xquad, yquad;

    //SETAR A PRECISAO DO NUMERO DE CASAS DO TIPO DE DADOS MPG
    //EM BITS = (NUM_DIGITS * log2(10) ) = 33219281
    //ISSO EH NECESSARIO, POIS A PRECISAO DA FUNCAO MPG EH DADA EM VALOR DE BITS

    mpf_set_default_prec(33219281);
    // prec = 1/(10^PREC)

    mpf_init(n);
    mpf_init(x);
    mpf_init(y);
    mpf_init(Pi);
    mpf_init(Pin);
    mpf_init(aux);
    mpf_init(xquad);
    mpf_init(yquad);

    //PEGA O TEMPO INICIAL DE EXECUCAO
    gettimeofday(&inicio, NULL);

    //Comeco do calculo
    srand(time(0));
    printf("RODANDO MÉTODO DE MONTE CARLO SEQUENCIAL...\n");
    for (i=0;i<MAX_INT;i++){
        printf("interacao: %ld\n", i);
        mpf_set_d(x, (double) rand()); //gera numero aleatorio
        mpf_div_ui(x,x,RAND_MAX); //divide pelo valor maximo de rand, assim fica entre 0 e 1
        mpf_set_d(y, (double) rand()); //gera numero aleatorio
        mpf_div_ui(y,y,RAND_MAX);

        mpf_mul(xquad, x, x);
        mpf_mul(yquad, y, y);
        mpf_add(aux, xquad, yquad); //x² + y²
      if (mpf_cmp_d(aux,1.0) <= 0) // <= R²
            mpf_add_ui(Pin, Pin, 1);
    }

    mpf_div_ui(aux, Pin, i);
    mpf_mul_ui(Pi, aux, 4);

    //Fim do calculo

    //SALVA O PI EM UM ARQUIVO TXT
    FILE *fp = fopen("monte_carlo_sequencial.txt", "w");
    // IMPREIME COM PRECISAO  DE 10000000 DIGITOS*/
    mpf_out_str(fp, 10, 10000000, Pi);
    fclose(fp);

    //PEGA O TEMPO FINAL DE EXECUCAO
    gettimeofday(&fim, NULL);

    //DIFERENCA ENTRE FINAL E INICIAL
    tempo = fim.tv_sec - inicio.tv_sec;

    printf("COMPLETO\nITERACOES: %d\n", MAX_INT);
    printf("TEMPO DE EXECUÇÃO %d segundos\n", tempo);

    mpf_clear(n);
    mpf_clear(x);
    mpf_clear(y);
    mpf_clear(Pi);
    mpf_clear(Pin);
    mpf_clear(aux);
    mpf_clear(xquad);
    mpf_clear(yquad);

    return 0;
}
